#include "./exec.h"
#include "../driver/sensor.h"
#include "../driver/cmd_uart.h"
#include "../driver/ctrl.h"
#include "../task/water_heat_task.h"
#include "../task/steam_heat_task.h"
#include "../task/draw_task.h"
#include "../driver/nozzle.h"
#include "../cfg/app_info.h"

namespace service::exec {

using namespace utils;
using namespace driver;
using namespace task;
using namespace cfg;

constexpr uint32_t DRAW_WATER_TIMEOUT = 120 * 1000;
constexpr uint32_t DRAW_SENSOR_CHECK_TIMEOUT = 5 * 1000;
constexpr uint32_t DRAW_LESS = 5;

Error draw_water(uint16_t ml) {
    drawTask.stop();
    sensor.flow_reset();
    ctrl.open(parts::V1);
    ctrl.open(parts::V2);
    ctrl.open(parts::WATER_PUMP);
    uint32_t time_count = 0;
    uint32_t time_less = 0;
    uint16_t cur = 0, last = 0;
    Error err;
    for (;;) {
        cur = sensor.flow_volume();
        if (cur >= ml) {
            break;
        }
        osDelay(100);
        time_count += 100;
        time_less += 100;
        if (time_count >= DRAW_WATER_TIMEOUT) {
            err = ec::DRAW_WATER_TIMEOUT;
            break;
        }
        if (time_less >= DRAW_SENSOR_CHECK_TIMEOUT) {
            time_less = 0;
            if (cur < (last + DRAW_LESS)) {
                err = ec::DRAW_SENSOR_FAIL;
                break;
            }
            last = cur;
        }
    }

finish:
    ctrl.close(parts::WATER_PUMP);
    ctrl.close(parts::V1);
    ctrl.close(parts::V2);
    drawTask.idle();
    return err;
}

Error wait_water_temp(uint8_t temp) {
    uint32_t time_count = 0;
    Error err;
    waterHeatTask.stop();
    ctrl.open(parts::HEAT_WATER);
    for (;;) {
        if (sensor.water_temp_value() > temp) {
            break;
        }
        osDelay(600);
        time_count += 600;
        if (time_count >= appInfo->water_heat_timeout) {
            err = ec::WATER_HEAT_TIMEOUT;
            break;
        }
    }
    ctrl.close(parts::HEAT_WATER);
    waterHeatTask.idle();
    return err;
}

Error nozzle_draw_water(uint16_t mm, uint8_t temp, uint16_t ml) {
    Error err = nozzle.run(mm);
    if (err) {
        goto finish;
    }
    
    err = wait_water_temp(temp);
    if (err) {
        goto finish;
    }
    
    err = draw_water(ml);
    if (err) {
        goto finish;
    }

finish:
    return err;
}

}

